/*
 * Copyright (c) 2009, Russell Weir
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE PROJECT CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */

package scripting;
import Type;

/**
* A Python scripting environment.
*
* <ul>
* <li>Python Dictionaries must only use string keys.
* <li>Haxe objects are passed to Python are converted to Dictionaries.
* <li>Haxe dates are passed to Python as a Dictionary DateObject
* </ul>
*
* @author Russell Weir
**/
class VmPython extends Vm
{
	public function new() {
		super(Vm.PYTHON);
		handle = vmpython_create();

		if(handle == null)
			throw "Unable to create vm";

		version = Converter.toHaxe(vmpython_getversion(handle));
		version = StringTools.replace(version,"\r\n", "");
		version = StringTools.replace(version,"\n", "");
		try {
			var numParts = version.split(" ").shift().split(".");
			versionMajor = Std.parseInt(numParts[0]);
			versionMinor = Std.parseInt(numParts[1]);
			versionRevision = Std.parseInt(numParts[2]);
		} catch(e:Dynamic) {}
	}

	public override function ucall(functionName:String,args:Array<Dynamic>) : Dynamic
	{
		return Converter.toHaxe(
			vmpython_call_function(
				handle,
				#if neko untyped functionName.__s, #else #error #end
				args));
	}

	public override function exec(code:String,chunkName:String=null) : Bool
	{
		return Converter.toHaxe(
			vmpython_exec(handle,
				#if neko untyped code.__s #else #error #end
			)
		);
	}

	public override function execBytes(code:haxe.io.Bytes,chunkName:String=null) : Bool
	{
		return Converter.toHaxe(
			vmpython_exec(handle, code.getData())
		);
	}

	public override function execFile(filename:String) : Dynamic
	{
		// This must be done with a bytes buffer, since there are
		// issues passing FILE pointers around in the DLL or shared
		// object
		// see http://effbot.org/pyfaq/pyrun-simplefile-crashes-on-windows-but-not-on-unix-why.htm
		var code = neko.io.File.getBytes(filename);
		return Converter.toHaxe(vmpython_exec(handle, code.getData()));
	}

	public override function getError() : String
	{
		return Converter.toHaxe(vmpython_get_error(handle));
	}

	/**
	* @todo implement
	**/
	public override function setPaths(paths:Array<String>) : Void
	{
//http://www.python.org/doc/2.3.5/inst/search-path.html
// 		vmpython_set_path(handle, Converter.toNeko(path));
	}

	////////////////////////////////////////////////////////////////////////
	////                    Private methods                             ////
	////////////////////////////////////////////////////////////////////////
	private override function makeVmDate(d:Dynamic) : Dynamic {
		if(Std.is(d, Date)) {
			d = DateObject.ofDate(cast d);
		}
		if(Std.is(d,DateObject))
			return vmpython_makenativedate(handle, cast(d,DateObject).toObject());
		throw "Invalid date object";
	}

	////////////////////////////////////////////////////////////////////////
	////                     Static methods                             ////
	////////////////////////////////////////////////////////////////////////
	static function __init__() {
		vmpython_initialize();
	}


	static var vmpython_initialize = neko.Lib.load("hxvmpython", "vmpython_initialize", 0);
	static var vmpython_call_function = neko.Lib.load("hxvmpython", "vmpython_call_function", 3);
	static var vmpython_create = neko.Lib.load("hxvmpython", "vmpython_create", 0);
	static var vmpython_exec = neko.Lib.load("hxvmpython", "vmpython_exec", 2);
	static var vmpython_get_error = neko.Lib.load("hxvmpython", "vmpython_get_error", 1);
	static var vmpython_getversion = neko.Lib.load("hxvmpython", "vmpython_getversion", 1);
// 	static var vmpython_load_bytes = neko.Lib.load("hxvmpython", "vmpython_load_bytes", 2);
	static var vmpython_makenativedate = neko.Lib.load("hxvmpython", "vmpython_makenativedate", 2);
	static var vmpython_openstdlib = neko.Lib.load("hxvmpython", "vmpython_openstdlib", 2);
// 	static var vmpython_set_path = neko.Lib.load("hxvmpython", "vmpython_set_path", 2);
}